
package nsga;

public class IndividuoTSP implements Cloneable, Individuo
{
    private int[] nodos;
    private int[] nodosInversos;
    private int length;
    private int n;//Cantidad de nodos en el grafo.
    private double[] fitness;
    private double fitnessAlgoritmo;
    private int cantidadDigitos;
    private int ultimoNodoInsertado;
    
    public IndividuoTSP(int length)
    {
        this.length=length;
        nodos=new int[this.length];
        nodosInversos=new int[this.length];
        for(int i=0;i<this.length;i++)
        {
            nodos[i]=-1;
            nodosInversos[i]=-1;
        }
        n=1;
        ultimoNodoInsertado=0;
        cantidadDigitos=(int)Math.pow(10, String.valueOf(length).length());
    }
    
    public boolean addNodo(int destino)
    {
        if(n==length)
        {
            return false;
        }
        else
        {
            if((ultimoNodoInsertado!=destino)&&(nodosInversos[destino]==-1)&&(nodos[destino]==-1))
            {
                   nodos[ultimoNodoInsertado]=destino;
                   nodosInversos[destino]=ultimoNodoInsertado;
                   ultimoNodoInsertado=destino;
                   n++;
                   if(n==length)
                   {
                        nodos[destino]=0;
                        nodosInversos[0]=destino;
                   }
                   return true;
            }
            else
            {
                return false;
            }
        }
    }
    
    public boolean isFull()
    {
        return n==length;
    }

    public static IndividuoTSP getIndividuoGeneradoAleatoriamente(int length)
    {
        IndividuoTSP individuoTSP=new IndividuoTSP(length);
        while(!individuoTSP.isFull())
        {
            do
            {
                int rand;
                do
                {
                    rand=(int)(Math.random()*individuoTSP.cantidadDigitos);
                }
                while(rand>=individuoTSP.length);
                if(individuoTSP.addNodo(rand))
                {
                       break;
                }
            }
            while(true);
        }
        return individuoTSP;
    }
    
    public double[] getFitness()
    {
        return fitness.clone();
    }
    
    public void setFitness(double[] fitness)
    {
        this.fitness=fitness;
    }
    
    public double getFitnessAlgoritmo()
    {
        return fitnessAlgoritmo;
    }

    public void setFitnessAlgoritmo(double fitnessAlgoritmo)
    {
        this.fitnessAlgoritmo = fitnessAlgoritmo;
    }
    
    public int[] getGrafo()
    {
        return nodos.clone();
    }

    public void mutar()
    {
        if(length>2)
        {
            int rand1;
            do
            {
                rand1=(int)(Math.random()*cantidadDigitos);
            }
            while((rand1>=length)||(rand1==0));
            int rand2;
            do
            {
                rand2=(int)(Math.random()*cantidadDigitos);
            }
            while((rand2>=length)||(rand2==0)||(rand1==rand2));
            if(nodos[rand1]==rand2)
            {
                nodos[rand1]=nodos[rand2];
                nodos[rand2]=rand1;
                nodos[nodosInversos[rand1]]=rand2;
                nodosInversos[rand2]=nodosInversos[rand1];
                nodosInversos[rand1]=rand2;
                nodosInversos[nodos[rand1]]=rand1;
            }
            else if(nodos[rand2]==rand1)
            {
                nodos[rand2]=nodos[rand1];
                nodos[rand1]=rand2;
                nodos[nodosInversos[rand2]]=rand1;
                nodosInversos[rand1]=nodosInversos[rand2];
                nodosInversos[rand2]=rand1;
                nodosInversos[nodos[rand2]]=rand2;
            }
            else
            {
                int tmp=nodos[rand1];
                nodos[rand1]=nodos[rand2];
                nodos[rand2]=tmp;
                nodos[nodosInversos[rand1]]=rand2;
                nodos[nodosInversos[rand2]]=rand1;
                tmp=nodosInversos[rand1];
                nodosInversos[rand1]=nodosInversos[rand2];
                nodosInversos[rand2]=tmp;
                nodosInversos[nodos[rand1]]=rand1;
                nodosInversos[nodos[rand2]]=rand2;
            }
        }
    }

    public Individuo clone()
    {
        IndividuoTSP individuoTSP=null;
        try
        {
            individuoTSP=(IndividuoTSP)super.clone();
        }
        catch(CloneNotSupportedException cloneNotSupportedException)
        {
        }
        individuoTSP.nodos=nodos.clone();
        individuoTSP.nodosInversos=nodosInversos.clone();
        individuoTSP.fitness=fitness.clone();
        return individuoTSP;
    }

    public static void isIndividuoValido(IndividuoTSP individuoTSP)
    {
        int[] prueba=new int[individuoTSP.length];
        int actual=0;
        prueba[0]++;
        for(int i=0;i<prueba.length-1;i++)
        {
            if(prueba[individuoTSP.nodos[actual]]>0)
            {
                throw new Error("Individuo TSP invalido!!!");
            }
            else
            {
                prueba[individuoTSP.nodos[actual]]++;
            }
            actual=individuoTSP.nodos[actual];
        }
        for(int i=0;i<prueba.length;i++)
        {
            if(prueba[i]!=1)
            {
                throw new Error("Individuo TSP invalido!!!");
            }
            else
            {
                prueba[i]=0;
            }
        }
        actual=0;
        prueba[0]++;
        for(int i=0;i<prueba.length-1;i++)
        {
            if(prueba[individuoTSP.nodosInversos[actual]]>0)
            {
                throw new Error("Individuo TSP invalido!!!");
            }
            else
            {
                prueba[individuoTSP.nodosInversos[actual]]++;
            }
            actual=individuoTSP.nodosInversos[actual];
        }
        for(int i=0;i<prueba.length;i++)
        {
            if(prueba[i]!=1)
            {
                throw new Error("Individuo TSP invalido!!!");
            }
        }
        
    }
}
